package com.hejjon.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hejjon.bean.FeatureFieldItem;
import com.hejjon.core.domain.entity.BasicType;
import com.hejjon.core.domain.entity.FeatureField;
import com.hejjon.core.enumer.DataViewTypeEnum;
import com.hejjon.core.enumer.DeleteFlagEnum;
import com.hejjon.core.enumer.FeatureFieldKindEnum;
import com.hejjon.core.enumer.JdbcTypeEnum;
import com.hejjon.core.exception.BusinessException;
import com.hejjon.core.utils.StrUtil;
import com.hejjon.domain.request.FeatureFieldBatchSaveRequest;
import com.hejjon.domain.request.FeatureFieldCreateRequest;
import com.hejjon.domain.response.FeatureFieldBatchSaveResponse;
import com.hejjon.domain.response.FeatureFieldCreateResponse;
import com.hejjon.domain.vo.FeatureFieldVO;
import com.hejjon.mapper.FeatureFieldMapper;
import com.hejjon.service.IBasicTypeService;
import com.hejjon.service.IBusinessFeatureService;
import com.hejjon.service.IFeatureFieldService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author: cs
 * @date: 2025-05-15 14:04:12
 * @since: 1.0
 */
@Service
public class FeatureFieldServiceImpl extends ServiceImpl<FeatureFieldMapper, FeatureField> implements IFeatureFieldService {


    @Autowired
    private IBasicTypeService basicTypeService;

    @Autowired
    private IBusinessFeatureService businessFeatureService;

    @Override
    public FeatureFieldCreateResponse create(FeatureFieldCreateRequest request) {

        boolean exist = existByNameAndFeatureId(request.getName(), request.getFeatureId());
        if (exist) {
            throw new BusinessException("当前业务对象已包含同名字段，请修改字段名称重试！");
        }
        String kind = request.getKind();
        FeatureFieldKindEnum typeEnum = FeatureFieldKindEnum.getInstance(kind);
        if (typeEnum == null) {
            throw new BusinessException("字段类型非法！");
        }

        JdbcTypeEnum jdbcTypeEnum = getJdbcType(typeEnum, request.getTypeId());
        FeatureField ff = new FeatureField();
        ff.setId(StrUtil.getUUID());
        ff.setName(request.getName());
        ff.setLabel(request.getLabel());
        ff.setFeatureId(request.getFeatureId());
        ff.setIsRef(request.getIsRef());
        ff.setKind(request.getKind());
        ff.setJdbcType(jdbcTypeEnum.getName());
        ff.setDeleteFlag(DeleteFlagEnum.NO.getCode());
        boolean stat = save(ff);
        FeatureFieldCreateResponse response = new FeatureFieldCreateResponse();
        if (stat) {
           response.returnSuccess();
        } else {
            response.returnFail();
        }
        return response;
    }

    @Override
    public boolean existByNameAndFeatureId(String name, String featureId) {
        LambdaQueryWrapper<FeatureField> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FeatureField::getName, name).eq(FeatureField::getDeleteFlag,DeleteFlagEnum.NO.getCode())
                .and(w1 -> w1.eq(FeatureField::getFeatureId, featureId));

        return exists(wrapper);
    }

    @Override
    public boolean removeByFeatureId(String featureId) {

        LambdaQueryWrapper<FeatureField> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FeatureField::getFeatureId, featureId);
        FeatureField entity = new FeatureField();
        entity.setDeleteFlag(DeleteFlagEnum.YES.getCode());
        entity.setUpdateBy("admin");
        entity.setUpdateTime(LocalDateTime.now());

        return update(entity, wrapper);
    }


    /**
     *  获取字段的存储类型 jdbcType
     * @param typeEnum
     * @param typeId
     * @return
     */
    private JdbcTypeEnum getJdbcType(FeatureFieldKindEnum typeEnum, String typeId) {
        if (typeEnum == null) {
            throw new BusinessException("未知的类型: typeId=[" + typeId + "]");
        }
        JdbcTypeEnum jdbcTypeEnum = null;
        switch (typeEnum) {
            case basicType:
            case busiAttr:
                BasicType basicType = basicTypeService.getById(typeId);
                String jdbcTypeCode = basicType.getJdbcTypeCode();
                jdbcTypeEnum = JdbcTypeEnum.getInstance(jdbcTypeCode);
                break;
            case feature:
                break;
            default:
                return JdbcTypeEnum.VARCHAR;
        }
        return jdbcTypeEnum;
    }

    @Transactional
    @Override
    public FeatureFieldBatchSaveResponse batchSave(FeatureFieldBatchSaveRequest request) {
        List<FeatureFieldItem> fieldList = request.getFieldList();
        // 1. 校验是否存在字段名称和字段显示名称为空的
        for (FeatureFieldItem fieldItem : fieldList) {
            String name = fieldItem.getName();
            String label = fieldItem.getLabel();
            if (StringUtils.isEmpty(name) || StringUtils.isEmpty(label)) {
                throw new BusinessException("存在为空的字段名称或显示名称,请检查后重试！");
            }
        }
        // 2. 校验是否存在同名字段
        Map<String, List<FeatureFieldItem>> group = fieldList.stream().collect(Collectors.groupingBy(FeatureFieldItem::getName));
        for (Map.Entry<String, List<FeatureFieldItem>> entry : group.entrySet()) {
            List<FeatureFieldItem> value = entry.getValue();
            if (value.size() > 1) {
                String key = entry.getKey();
                throw new BusinessException("存在相同名称的字段,字段名称为: " + key);
            }
        }
        // 3. 整理类型map
        List<String> typeIdList = fieldList.stream().map(FeatureFieldItem::getTypeId).distinct().collect(Collectors.toList());
        List<BasicType> basicTypeList = basicTypeService.findByIds(typeIdList);
        // id -- jdbcTypeName Map
        Map<String, String> jdbcTypNameMap = basicTypeList.stream().collect(Collectors.toMap(BasicType::getId, BasicType::getJdbcTypeCode));

        // 4. 整理新增、更新的字段列表
        List<FeatureField> addFieldList = new ArrayList<>();
        List<FeatureField> updateFieldList = new ArrayList<>();
        fieldList.forEach(fieldItem -> {
            if (StringUtils.isEmpty(fieldItem.getId())) {
                // 新增的字段
                FeatureField field = new FeatureField();
                field.setId(StrUtil.getUUID());
                field.setFeatureId(request.getFeatureId());
                field.setName(fieldItem.getName());
                field.setLabel(fieldItem.getLabel());
                String kind = fieldItem.getKind();
                field.setTypeId(fieldItem.getTypeId());
                field.setBusiAttrId(fieldItem.getBusiAttrId());
                field.setKind(kind);
                field.setDefaultValue(fieldItem.getDefaultValue());
                field.setDescription(fieldItem.getDescription());
                field.setDeleteFlag(DeleteFlagEnum.NO.getCode());
                FeatureFieldKindEnum kindEnum = FeatureFieldKindEnum.getInstance(kind);
                int isRef = kindEnum == FeatureFieldKindEnum.feature ? 1 : 0;
                field.setIsRef(isRef);
                String jdbcTypeName = jdbcTypNameMap.get(fieldItem.getTypeId());
                field.setJdbcType(jdbcTypeName);
                field.setCreateBy("admin");
                field.setCreateTime(LocalDateTime.now());
                addFieldList.add(field);
            } else {
                // 更新的字段
                FeatureField field = new FeatureField();
                field.setId(fieldItem.getId());
                field.setFeatureId(request.getFeatureId());
                field.setName(fieldItem.getName());
                field.setLabel(fieldItem.getLabel());
                String kind = fieldItem.getKind();
                field.setTypeId(fieldItem.getTypeId());
                field.setBusiAttrId(fieldItem.getBusiAttrId());
                field.setKind(kind);
                FeatureFieldKindEnum kindEnum = FeatureFieldKindEnum.getInstance(kind);
                int isRef = kindEnum == FeatureFieldKindEnum.feature ? 1 : 0;
                field.setIsRef(isRef);
                String jdbcTypeName = jdbcTypNameMap.get(fieldItem.getTypeId());
                field.setDefaultValue(fieldItem.getDefaultValue());
                field.setDescription(fieldItem.getDescription());
                field.setJdbcType(jdbcTypeName);
                field.setUpdateBy("admin");
                field.setUpdateTime(LocalDateTime.now());
                updateFieldList.add(field);
            }
        });

        boolean stat1 = false, stat2 = false;
        if (!addFieldList.isEmpty()) {
            stat1 = saveBatch(addFieldList);
        }
        if (!updateFieldList.isEmpty()) {
            stat2 = updateBatchById(updateFieldList);
        }
        FeatureFieldBatchSaveResponse response = new FeatureFieldBatchSaveResponse();
        if (stat1 || stat2) {
            response.returnSuccess();
        } else {
            response.returnFail();
        }
        return response;
    }

    @Override
    public List<FeatureFieldVO> findByFeatureId(String featureId) {
        List<FeatureFieldVO> voList = baseMapper.selectByFeatureId(featureId);
        return voList.stream().peek(item -> item.setViewType(DataViewTypeEnum.getCodeByTypeName(item.getTypeName())))
                .collect(Collectors.toList());
    }

    @Override
    public boolean removeByFieldId(String fieldId, String deleteFlag) {
        LambdaQueryWrapper<FeatureField> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FeatureField::getId, fieldId);

        FeatureField entity = new FeatureField();
        entity.setDeleteFlag(deleteFlag);
        entity.setUpdateBy("admin");
        entity.setUpdateTime(LocalDateTime.now());
        return update(entity, wrapper);
    }

    @Override
    public boolean batchRemoveByFieldId(List<String> fieldIds, String deleteFlag) {
        LambdaQueryWrapper<FeatureField> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(FeatureField::getId, fieldIds);

        FeatureField entity = new FeatureField();
        entity.setDeleteFlag(deleteFlag);
        entity.setUpdateBy("admin");
        entity.setUpdateTime(LocalDateTime.now());
        return update(entity, wrapper);
    }
}
